//
//  BAOAuthViewModel.swift
//  BAweibo
//
//  Created by baggio on 2017/8/14.
//  Copyright © 2017年 baggio. All rights reserved.
//

import UIKit


//ViewModel 帮 Controller 请求数据，处理业务逻辑，存取数据

class BAOAuthViewModel: NSObject {
    
    //单例
    static let share:BAOAuthViewModel=BAOAuthViewModel()
    
    //oAuthModel 不要每次都从沙盒中取，第一次从沙盒中取，以后都从内存中取
    var oAuthModel:BAOAuthModel?
    
    //AccessToken 是否过期，计算属性（跟懒加载比较，没有=，没有()）
    var isAccessTokenExpired:Bool{
        if oAuthModel?.expires_date?.compare(Date()) == ComparisonResult.orderedDescending{
            return false
        }
        return true
    }
    
    //是否登录，其实这个属性没必要，用 !isAccessTokenExpired 即可
    var isLogin:Bool{
        return oAuthModel?.access_token != nil && !isAccessTokenExpired
    }
    
    //因为是单例，所以构造函数改成 private
    private override init(){
        super.init()
        
        //第一次从沙盒中取
        oAuthModel=getOAuthModelFromSandbox()
        
        //判断 AccessToken 是否过期
        if isAccessTokenExpired{
            oAuthModel=nil
        }
    }
    
    //沙盒路径
    let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
    //在 path 下面自己定义一个文件 oAuthModel.plist
    //String 没有拼接方法，所以要转成 NSString
    var oAuthModelFile:String{
        return (path as NSString).appendingPathComponent("oAuthModel.plist")
        ///Users/baggio/Library/Developer/CoreSimulator/Devices/EB1EEAB5-36D1-421C-9C44-ED6C04D8FFA1/data/Containers/Data/Application/487D5EFA-F3E6-431C-9E15-5C6D0076CD6B/Documents/oAuthModel.plist
    }
    
    //获取 AccessToken
    //添加一个闭包参数，表示成功或失败
    func loadAccessToken(code:String,finished:@escaping (Bool)->()){
        
        BANetworkingTools.share.loadOAuthAccessToken(code: code, success: { (response) in
            //print(response)
            /*
             Optional({
             "access_token" = "2.002tCPqBH9k1mD0a7c8e7d1bdIXX1D";
             "expires_in" = 157679999;
             "remind_in" = 157679999;
             uid = 1688088343;
             })
             
             经测试，code 每次都不一样，但是 access_token 都一样
             */
            
            //json object 如果不空就转 dict，再 dict 转 model
            guard let res=response as? [String:Any] else{
                finished(false)
                return
            }
            
            // 用 YYModel
            // 加上 guard 是为了把 oAuthModel 从可选值变成必选值，后面用起来方便些
            guard let oAuthModel = BAOAuthModel.yy_model(withJSON: res) else{
                finished(false)
                return
            }
            //            //用 KVC
            //            let oAuthModel = BAOAuthModel(dict: res)
            print(oAuthModel)
            
            //获取用户信息
            //在闭包中访问分类，self 不能少
            //            self.loadUserInfo(oAuthModel: oAuthModel)
            
            // isFinish: isFinish 把闭包参数传递给下一个函数
            self.loadUserInfo(oAuthModel: oAuthModel, finished: finished)
            
        }) { (error) in
            print("loadAccessToken 失败",error)
            finished(false)
        }
        
        
        
        /*
         改用 封装在 BANetworkingTools 中的方法
         
         let urlString="https://api.weibo.com/oauth2/access_token"
         let params=[
         "client_id":BA_Weibo_AppKey,
         "client_secret":BA_Weibo_AppSecret,
         "grant_type":"authorization_code",
         "code":code,
         "redirect_uri":BA_Weibo_Redirect_Uri
         ]
         
         BANetworkingTools.share.request(type: BANetworkingToolsType.post, urlString: urlString, parameters: params, success: { (response) in
         //print(response)
         /*
         Optional({
         "access_token" = "2.002tCPqBH9k1mD0a7c8e7d1bdIXX1D";
         "expires_in" = 157679999;
         "remind_in" = 157679999;
         uid = 1688088343;
         })
         
         经测试，code 每次都不一样，但是 access_token 都一样
         */
         
         //json object 如果不空就转 dict，再 dict 转 model
         guard let res=response as? [String:Any] else{
         finished(false)
         return
         }
         
         // 用 YYModel
         // 加上 guard 是为了把 oAuthModel 从可选值变成必选值，后面用起来方便些
         guard let oAuthModel = BAOAuthModel.yy_model(withJSON: res) else{
         finished(false)
         return
         }
         //            //用 KVC
         //            let oAuthModel = BAOAuthModel(dict: res)
         print(oAuthModel)
         
         //获取用户信息
         //在闭包中访问分类，self 不能少
         //            self.loadUserInfo(oAuthModel: oAuthModel)
         
         // isFinish: isFinish 把闭包参数传递给下一个函数
         self.loadUserInfo(oAuthModel: oAuthModel, finished: finished)
         
         }) { (error) in
         print("loadAccessToken 失败",error)
         finished(false)
         }
         
         
         /*
         因为 AFN 已经把返回的数据进行了反序列化，所以看不出原始数据类型，
         用这种方式可以看出来 expires_in 是 Int，不是官方文档写的 String。"remind_in":"157679999","expires_in":157679999
         */
         //        let manager:AFHTTPSessionManager=AFHTTPSessionManager()
         //        //设置数据格式是二进制
         //        manager.responseSerializer=AFHTTPResponseSerializer()
         //        //用 AFN 中的 post 方法
         //        manager.post(urlString, parameters: params, progress: nil, success: { (_, result) in
         //            let json=NSString(data: (result as! NSData) as Data, encoding:String.Encoding.utf8.rawValue)
         //            print(json)
         //        }, failure: nil)
         
         */
    }
    
    
    //获取用户信息，通过 access_token 和 uid 获取 screen_name 和 avatar_large
    private func loadUserInfo(oAuthModel:BAOAuthModel,finished:@escaping (Bool)->()){
        
        BANetworkingTools.share.loadOAuthUserInfo(oAuthModel: oAuthModel, success: { (response) in
            //print(response)
            //json object 转 dict
            guard let res=response as? [String:Any] else{
                finished(false)
                return
            }
            
            //res["screen_name"] 是 Any?，要转成 String?
            oAuthModel.screen_name=res["screen_name"] as? String
            oAuthModel.avatar_large=res["avatar_large"] as? String
            print(oAuthModel)
            
            //归档，保存到沙盒
            self.saveOAuthModelToSandbox(oAuthModel: oAuthModel)
            
            //不用再往下传了，表示 load 成功
            finished(true)
            
        }) { (error) in
            print("loadUserInfo 失败",error)
            finished(false)
        }
        
        
        /*
         改用 封装在 BANetworkingTools 中的方法
         
         let urlString="https://api.weibo.com/2/users/show.json"
         let params=[
         "access_token":oAuthModel.access_token,
         "uid":oAuthModel.uid
         ]
         
         BANetworkingTools.share.request(type: .get, urlString: urlString, parameters: params, success: { (response) in
         //print(response)
         //json object 转 dict
         guard let res=response as? [String:Any] else{
         finished(false)
         return
         }
         
         //res["screen_name"] 是 Any?，要转成 String?
         oAuthModel.screen_name=res["screen_name"] as? String
         oAuthModel.avatar_large=res["avatar_large"] as? String
         print(oAuthModel)
         
         //归档，保存到沙盒
         saveOAuthModelToSandbox(oAuthModel: oAuthModel)
         
         //不用再往下传了，表示 load 成功
         finished(true)
         
         }) { (error) in
         print("loadUserInfo 失败",error)
         finished(false)
         }
         */
    }
    
}


//oAuthModel 归档/解档
extension BAOAuthViewModel{
    
    //保存 oAuthModel 数据到沙盒
    func saveOAuthModelToSandbox(oAuthModel:BAOAuthModel) {
        
        //保存到沙盒的时候，也给内存中赋值
        //如果没有这句话，第一次登录 app 的时候，init()的时候，沙盒中还没有值，而以后再登录 app ，因为 BAOAuthViewModel 是单例，所以不会再执行init()中的 getOAuthModelFromSandbox()，所以永远取不到值
        self.oAuthModel=oAuthModel
        
        //归档
        NSKeyedArchiver.archiveRootObject(oAuthModel, toFile: oAuthModelFile)
    }
    
    //从沙盒获取 oAuthModel 数据
    func getOAuthModelFromSandbox() -> BAOAuthModel? {
        //解档
        return NSKeyedUnarchiver.unarchiveObject(withFile: oAuthModelFile) as? BAOAuthModel
    }
}
